package com.handy.plugin.data;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.handy.database.DBUtil;
import com.handy.database.page.DBUtilPage;
import com.handy.util.DateTool;
import com.handy.util.FileTool;
import com.handy.webwork.action.ActionForm;
import com.handy.webwork.config.HandyConfiguration;

public class ScriptAction extends Action {
	
	public String execute() {
		boolean scExist = true;
		if (scriptid == null || "".equals(scriptid) || null == ScriptCache.findScript(scriptid)) {
			// 如果设置extendScriptFile
			if (null != ScriptCache.getInstance().getExtendScriptFile()) {
				ScriptCache.loadOutScript();
				if (scriptid == null || "".equals(scriptid) || null == ScriptCache.findScript(scriptid)) {
					scExist = false;
				}
			}else {
				scExist = false;
			}
		}
		if(!scExist){
			errorCode = 1;
			log.error("未找到编号\""+scriptid+"\"的脚本！");
			retString = "未找到编号\""+scriptid+"\"的脚本！";
		}else{
			scriptBean = ScriptCache.findScript(scriptid);
			invoke();
		}
		String ret = "";
		
		switch (outputFileFormat){
		case 1://输出html
			ret = "html";
			break;
		case 2://输出xml
			ret = "xml";
			break;
		case 3://输出josn
			ret = "json";
			break;
		default:
			ret = "json";
			break;
		}
		
		//是否使用定义模板
		if (vars.get(HANDY_DYNA_FTL) != null && !"".equals(vars.get(HANDY_DYNA_FTL))){
			ret = HANDY_DYNA_FTL;
		}
		
		//是否直接由脚本输出页面
		if (vars.get(HANDY_ACTION_RESPONSE) != null){
			ret = HANDY_ACTION_RESPONSE;
		}
		
		return ret;
	}
	
	private void invoke(){
		if (scriptBean==null) return;
		
		ScriptEngineManager factory = new ScriptEngineManager();
		ScriptEngine engine = factory.getEngineByName("JavaScript");
		Compilable compilable = (Compilable) engine;
		try {
			CompiledScript compiled = compilable.compile(scriptBean.getFileContent());
			//获取其它表对应的字段
			//key:设定的字段名,value:取数据的sql语句
			vars.put(V_EXPEND_COLUMN, new HashMap<String,String>());
			vars.put(V_MAP_COLUMN, new HashMap<String,HashMap<String,String>>());
			engine.put("run", true);//此时一定要设置为ture，执行脚本逻辑。
			//传递给脚本各种所需参数
			engine.put("action", this);
			compiled.eval();
			//以哪种文件格式输出
			if(null != vars.get(V_OUTPUT_FILE_FORMAT)){
				outputFileFormat = Integer.valueOf((String)vars.get(V_OUTPUT_FILE_FORMAT));
			}
			
			//数据源
			if(null != vars.get(V_DATA_SOURCE_NAME)){
				dataSourceName = (String)vars.get(V_DATA_SOURCE_NAME);
			}
			
			if (vars.get(V_TABLE_NAME) != null && !"".equals(vars.get(V_TABLE_NAME))){
				//数据列表输出
				findDataList();
			}
			
		} catch (ScriptException e) {
			log.error(e.getMessage()+" scid = " + scriptid);
		}
	}
	
	
	/**
	 * 输出数据
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private void findDataList(){

		int maxLine = 0;
		if (null != vars.get(V_MAX_LINE)){
			maxLine = Integer.valueOf((String)vars.get(V_MAX_LINE));
		}

		String tableName = "";
		if (null != vars.get(V_TABLE_NAME)){
			tableName = (String)vars.get(V_TABLE_NAME);
		}
		
		String columns = "*";
		if (null != vars.get(V_COLUMNS)){
			columns = (String)vars.get(V_COLUMNS);
		}
		
		String condition = "";
		if (null != vars.get(V_CONDITION)){
			condition = (String)vars.get(V_CONDITION);
		}
		
		int pageListCount = 10;
		if (null != vars.get(V_PAGE_LIST_COUNT)){
			pageListCount = Integer.valueOf((String)vars.get(V_PAGE_LIST_COUNT));
		}
		
		if (maxLine>0){//为分页处理时
			page = new DBUtilPage();
			page.setTableName(tableName);//1.设置表名
			page.setColumns(columns);//2.设置字段列表
			page.setFindCondition(condition);//3.设置查询条件
			page.setMaxLine(maxLine);//每页显示最大行数
			page.setPageListCount(pageListCount);//页列表
			page.setDataSourceName(dataSourceName);//数据源
			page.setDbKind(ScriptCache.getInstance().getDbKind());//数据库类型
			page.setSpecify(pageno);//指定页码
			page.query();
			querySQL = page.getQuerySQL();
			expandColumn(page.getRecorders());//处理扩展字段,用于一对多。
			mapColumn(page.getRecorders());//处理映射字段,用于一对一。
		}else{//返回所有
			StringBuffer sb = new StringBuffer();
			sb.append("select ").append(columns).append(" from ");
			sb.append(tableName).append(" ").append(condition);
			//querySQL = sb.toString();
//			log.info(sb.toString());
			ResultSetHandler h = new MapListHandler();
			QueryRunner run = new QueryRunner(dbUtil.dataSource(dataSourceName));
			try {
				recorders = (ArrayList)run.query(sb.toString(), h );
				expandColumn(recorders);//处理扩展字段,用于一对多。
				mapColumn(recorders);//处理映射字段,用于一对一。
			} catch (SQLException e) {
				log.error(e.getMessage());
			}
		}
	}
	
	/**
	 * 处理扩展字段。
	 * @param rs
	 */
	@SuppressWarnings({ "unused", "unchecked" })
	private void expandColumn(ArrayList rs) {
		HashMap<String, String> ecs = (HashMap<String, String>) vars.get(V_EXPEND_COLUMN);
		if (ecs == null || ecs.size() == 0) return;

		// 遍历结果集，取扩展字段
		// for (Object recorder:rs){
		for (Iterator iter = rs.iterator(); iter.hasNext();) {
			HashMap _recorder = (HashMap) iter.next();// 强制类型转换
			// 遍历扩展字段MAP
			Set<Entry<String, String>> ecsEntrys = ecs.entrySet();
			for (Map.Entry<String, String> ecsEntry : ecsEntrys) {
				String ecsKey = ecsEntry.getKey();// 扩展字段名
				String ecsSQL = ecsEntry.getValue();// 取扩展字段SQL语句
				if (ecsKey == null || "".equals(ecsKey) || ecsSQL == null || "".equals(ecsSQL)) {
					log.error("扩展字段名与对应取值的sql语句都不能为空。");
					continue;// 跳出
				}
				// 处理SQL语句..开始
				Set<Entry> entrys = _recorder.entrySet();
				for (Map.Entry entry : entrys) {
					String colName = (String) entry.getKey();
					Object colValue = (Object) entry.getValue();
					ecsSQL = ecsSQL.replaceAll("#" + colName + "#", String.valueOf(colValue));
				}
				// log.info(ecsSQL);
				// 简单判断是否为SQL语句
				if(ecsSQL.indexOf("select")==-1) {
					_recorder.put(ecsKey, ecsSQL);
				}else{
					ResultSetHandler h = new MapListHandler();
					QueryRunner run = new QueryRunner(dbUtil.dataSource(dataSourceName));
					try {
						_recorder.put(ecsKey, (ArrayList) run.query(ecsSQL, h));
					} catch (SQLException e) {
						log.error(e.getMessage());
					}
				//处理SQL语句..结束
				}
			}
		}
	}
	
	/**
	 * 处理映射字段
	 * @param hm
	 */
	@SuppressWarnings("unchecked")
	private void mapColumn(ArrayList rs){
		HashMap<String,HashMap<String,String>> mcs = (HashMap<String,HashMap<String,String>>)vars.get(V_MAP_COLUMN);
		if(mcs ==null || mcs.size()==0) return;
		
		//遍历结果集
		for (Iterator iter = rs.iterator();iter.hasNext();){
			HashMap _recorder = (HashMap)iter.next();//强制类型转换
			//遍历V_MAP_COLUMN
			Set<Entry<String,HashMap<String,String>>> mcsEntrys = mcs.entrySet();
			for (Map.Entry<String,HashMap<String,String>> mcsEntry : mcsEntrys) {
				String mcsKey = mcsEntry.getKey();//RS扩展字段名,如state_cn
				HashMap<String,String> mcsValue = mcsEntry.getValue();//取映射map, 即js中buildHashMap
				//取要映射的field
				String _field = mcsValue.get(V_MAPED_COLUMN);
				//取出本条记录对应的字段值.如state=0
				String _fieldValue = String.valueOf(_recorder.get(_field));
				//有可能下面_newFiledVaule为null,
				//可能是原来有对应值,但修改了扩展权限表(如业务表),或是扩展节点的查询条件改变引起
				String _newFiledVaule = mcsValue.get(_fieldValue);
				_recorder.put(mcsKey, _newFiledVaule);
			}
		}
	}
	
	/**
	 * 文件上传
	 * @param fileKey form的key值
	 * @param filePath 文件的保存路径
	 * @param fileName 保存的文件名，通常和原文件名不一样，可以是ID号，或时间字符串
	 * @param timePath 是否在文件的保存路径中生成日期目录
	 */
	public void uploadFile(String fileKey,String filePath,String fileName,boolean timePath){
		DiskFileItem diskFileItem = form.getDiskFileItem(fileKey);
		if (null == diskFileItem) return;//没有指定要保存的文件，结束处理。
		
		String rootPath = HandyConfiguration.rootPath();
		String separator = System.getProperty("file.separator");
		String time = DateTool.format(Calendar.getInstance().getTime(), false);
		//处理保存的文件路径(相对路径)
		if (filePath != null && !"".equals(filePath)) {
			if (filePath.startsWith("/")) {
				filePath = filePath.substring(1);
			}
			if (!filePath.endsWith("/")){
				filePath = filePath+"/";
			}
			if (timePath){//如果要生成日期目录
				filePath = filePath + time + "/";
			}
		} else {
			if (timePath){
				filePath = "upload/"+time + "/";
			}else{
				filePath = "upload/";
			}
		}

		// 创建存储文件的目录
		FileTool.creatDirs(rootPath + filePath);
		// 文件大小(单位K)
		long size = diskFileItem.getSize()/1024;
		if(size==0) size = 1;
		vars.put(fileKey + "_size", size);
		// 原文件名
		String sourceFileName = diskFileItem.getName();
		vars.put(fileKey + "_name", sourceFileName.substring(sourceFileName
				.lastIndexOf(separator) + 1));// 原文件名写到变量key_"name"
		
		File file = diskFileItem.getStoreLocation();
		if (null == file)
			return;
		if (null != file.getName() && !"".equals(file.getName())) {
			String suff = sourceFileName.substring(sourceFileName
					.lastIndexOf('.'));// 后缀
			// 没指定保存的文件名则系统自动生成
			if (fileName == null || "".equals(fileName)) {
				fileName = DateTool.getTimeString(DateTool.YYMMDDhhmmssxxx)
						+ suff;
			}
			// 上传到服务器上的文件名及绝对路径
			String targetFile = rootPath + filePath  + fileName;
			try {
				FileOutputStream fos = new FileOutputStream(targetFile);
				FileInputStream fis = new FileInputStream(file);
				byte[] buffer = new byte[1024];
				int len = 0;
				while ((len = fis.read(buffer)) > 0) {
					fos.write(buffer, 0, len);
				}
				// log.info("上传文件["+sourceFileName+"],保存到["+targetFile+"]");
				// 将存储路径写到变量key_"path"
				vars.put(fileKey + "_path", (rootPath + filePath  + fileName).replace("\\", "/"));
			} catch (FileNotFoundException e) {
				log.error(e.getMessage());
			} catch (IOException e) {
				log.error(e.getMessage());
			}
		}
	}
	
	/**
	 * 文件下载
	 * @param filepath 要下载的服务器上的文件路径
	 * @return
	 */
	public void download(String filepath){
		filepath="D:\\workspaces\\handy_application\\WebRoot\\fileupload\\2\\110117140421096.zip";
//		String filepath = getDownfilename();
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        OutputStream fos = null;
        InputStream fis = null;
        
        File downFile = new File(filepath);
        try {
			fis = new FileInputStream(downFile);
		} catch (FileNotFoundException e1) {
			log.error(e1.getMessage());
		}
        bis = new BufferedInputStream(fis);
        try {
			fos = getResponse().getOutputStream();
		} catch (IOException e1) {
			log.error(e1.getMessage());
		}
        bos = new BufferedOutputStream(fos);
        //这个就就是弹出下载对话框的关键代码
        String mimetype  =   null ;
//        mimetype  =  application.getMimeType( filePath );
        if ( mimetype == null)  mimetype  =   "application/octet-stream;charset=UTF-8 " ;
        getResponse().setContentType( mimetype );
         getResponse().setContentLength((int)downFile.length());
        getResponse().setHeader("Content-disposition", "attachment;filename=" + downFile.getName());
        int bytesRead = 0;
        byte[] buffer = new byte[8192];
        try {
			while ((bytesRead = bis.read(buffer, 0, 8192)) != -1) {
			    bos.write(buffer, 0, bytesRead);
			}
			bos.flush();
	        fis.close();
	        bis.close();
	        fos.close();
	        bos.close();
		} catch (IOException e) {
			log.error(e.getMessage());
		}
	}
	
	
	@SuppressWarnings("unchecked")
	public HashMap sendData() {
		//传入验证对象authority
		root.putAll(super.sendData());
		if (scriptBean != null){
			if (page!=null){
				root.put("page", page);
			}
			if (recorders != null){
				root.put("recorders", recorders);
			}
			root.put("params", params);
			switch (outputFileFormat){
			case 1://输出html
				root.put(HANDY_DYNA_FTL_CONTENT_TYPE, "text/html");
				break;
			case 2://输出xml
				root.put(HANDY_DYNA_FTL_CONTENT_TYPE, "text/xml");
				break;
			case 3://输出josn
				root.put(HANDY_DYNA_FTL_CONTENT_TYPE, "application/json");
				break;
			default:
				root.put(HANDY_DYNA_FTL_CONTENT_TYPE, "application/json");
				break;
			}
			//是否使用定义模板
			if (vars.get(HANDY_DYNA_FTL) != null && !"".equals(vars.get(HANDY_DYNA_FTL))){
				root.put(HANDY_DYNA_FTL, vars.get(HANDY_DYNA_FTL));
			}
			//如果定义了HANDY_DYNA_FTL_CONTENT_TYPE则直接使用HANDY_DYNA_FTL_CONTENT_TYPE所定义的格式输出
			if (vars.get(HANDY_DYNA_FTL_CONTENT_TYPE) != null && !"".equals(vars.get(HANDY_DYNA_FTL_CONTENT_TYPE))){
				root.put(HANDY_DYNA_FTL_CONTENT_TYPE, vars.get(HANDY_DYNA_FTL_CONTENT_TYPE));
			}
		}
		root.put("errorcode", errorCode);
		root.put("retstring", retString);
		return root;
	}
	
	public void getForm(ActionForm form) {

		this.form = form;
		
		if (null != form.getObject("scid") && !"".equals(form.getString("scid"))){
			scriptid = form.getString("scid");
		}
		// 当前页码
		if (null!=form.getObject("pageno")){
			pageno = form.getInteger("pageno");
		}
	}
	
	public void out(String outString){
		try {
			getResponse().getWriter().print(outString);

		} catch (IOException e) {
			log.error(e.getMessage());
		}
	}
	
	/**
	 * 创建ArrayList
	 * @return
	 */
	public ArrayList<Object> buildArrayList(){
		return new ArrayList<Object>();
	}
	
	/**
	 * 创建HashMap
	 * @return
	 */
	public HashMap<String,String> buildHashMap(){
		return new HashMap<String,String>();
	}
	
	/**
	 * 创建HashMap,通过指定的sql查询语句以及用于key以及value的字段填充HashMap
	 * @param sql
	 * @param keyCol
	 * @param valueCol
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public HashMap<String,String> buildHashMap(String sql,String keyCol,String valueCol){
		return buildHashMap(sql,keyCol,valueCol,0);
	}
	
	/**
	 * 创建HashMap,通过指定的sql查询语句以及用于key以及value的字段填充HashMap
	 * @param sql
	 * @param keyCol
	 * @param valueCol
	 * @param valueFormat value显示方式
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public HashMap<String,String> buildHashMap(String sql,String keyCol,String valueCol,int valueFormat){
		HashMap<String,String> map = new HashMap<String,String>();
		ResultSetHandler h = new MapListHandler();
		QueryRunner run = new QueryRunner(dbUtil.dataSource(dataSourceName));
		ArrayList rs = null;
		try {
			rs = (ArrayList)run.query(sql, h );
		} catch (SQLException e) {
			log.error(e.getMessage());
		}
		if (rs != null){
			//遍历结果集
			for (Iterator iter = rs.iterator();iter.hasNext();){
				HashMap _recorder = (HashMap)iter.next();//强制类型转换
				String key = String.valueOf(_recorder.get(keyCol));
//				System.out.println(key);
				String value = String.valueOf(_recorder.get(valueCol));
				if (valueFormat == 1) value = value + "("+ key +")";
//				System.out.println(value);
				map.put(key, value);
			}
		}		
		return map;
	}
	
	public Object buildClass(String className){
		Object o = null;
		 try {
			o = (Object) Class.forName(className).newInstance();
		} catch (ClassNotFoundException e) {
			log.error(e.getMessage());
		} catch (InstantiationException e) {
			log.error(e.getMessage());
		} catch (IllegalAccessException e) {
			log.error(e.getMessage());
		}
		
		return o;
	}
	
	private DBUtil dbUtil = DBUtil.getInstance();
	private ActionForm form = null;
	private String scriptid="";
	private ScriptBean scriptBean = null;
	private Integer pageno = 1;//当前页
	private DBUtilPage page = null;
	private String dataSourceName="";
	private String retString = "-";
	private ArrayList<Object> recorders = null;
	public String querySQL = "";//sql查询语句
	
	public void setRecorders(ArrayList<Object> rs){
		this.recorders = rs;
	}
	
	@SuppressWarnings("unchecked")
	private HashMap root = new HashMap();
	
	private int outputFileFormat = 3;//默认输出为json格式
	
	/**
	 * 与脚本交流存储变量的MAP
	 */
	private HashMap<String,Object> vars = new HashMap<String,Object>();
	
	/**
	 * 需要返回的页面参数
	 */
	private HashMap<String,String> params = new HashMap<String,String>();
	
	private Integer errorCode = 0;//0为没有错误
	
	@SuppressWarnings("unchecked")
	public HashMap getRoot(){
		return root;
	}
	
	public ActionForm getForm(){
		return form;
	}
	
	public DBUtil getDbUtil(){
		return dbUtil;
	}

	public HashMap<String,Object> getVars() {
		return vars;
	}
	
	public HashMap<String,String> getParams(){
		return params;
	}
	
	public Integer getErrorCode(){
		return errorCode;
	}
	
	public String getRetString(){
		return retString;
	}

	private static Log log = LogFactory.getLog(ScriptAction.class);
	
	/**
	 * <p>输出文件的格式,分三种格式：</p>
	 * 1.html格式输出<br>
	 * 2.xml格式输出<br>
	 * 3.json格式输出<br>
	 */
	public static final String V_OUTPUT_FILE_FORMAT = "v_output_file_format";
	
	public static final String V_DATA_SOURCE_NAME = "v_data_source_name";
	public static final String V_TABLE_NAME = "v_table_name";
	public static final String V_COLUMNS = "v_columns";
	public static final String V_CONDITION = "v_condition";
	public static final String V_MAX_LINE = "v_max_line";
	public static final String V_PAGE_LIST_COUNT = "v_page_list_count";
	
//	public static final String V_FTL_TEMPLATE = "v_ftl_template";
//	public static final String V_FTL_CONTENT_TYPE = "v_ftl_content_type";
	
	public static final String V_EXPEND_COLUMN = "v_expend_column";
	public static final String V_MAP_COLUMN = "v_map_column";
	public static final String V_MAPED_COLUMN = "v_maped_column";

	public void setRetString(String retString) {
		this.retString = retString;
	}

	public void setErrorCode(Integer errorCode) {
		this.errorCode = errorCode;
	}	
}
